package com.bpmn.flow.handler;

import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.util.StrUtil;
import com.bpmn.common.constant.BpmnModelConstants;
import com.bpmn.common.enums.TaskOperationEnum;
import com.bpmn.common.enums.TimeoutStrategy;
import com.bpmn.flow.dto.TaskOperationDTO;
import com.bpmn.flow.service.TaskOperationService;
import com.bpmn.utils.ModelUtils;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.constants.BpmnXMLConstants;
import org.flowable.bpmn.model.UserTask;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.jobexecutor.TimerEventHandler;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.job.service.JobHandler;
import org.flowable.job.service.impl.persistence.entity.JobEntity;
import org.flowable.task.api.Task;
import org.flowable.variable.api.delegate.VariableScope;

/**
 * 办理超时(过期)任务
 *
 * @author rain
 */
@Slf4j
public class TaskTimeoutJobHandler extends TimerEventHandler implements JobHandler {

    public static final String TYPE = "taskTimeout";

    private final TaskOperationService taskOperationService;

    public TaskTimeoutJobHandler(TaskOperationService taskOperationService) {
        this.taskOperationService = taskOperationService;
    }

    @Override
    public String getType() {
        return TYPE;
    }

    @Override
    public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) {
        if (StrUtil.isBlank(configuration)) {
            log.warn("Invalid configuration: {}", configuration);
            return;
        }
        TaskService taskService = CommandContextUtil.getProcessEngineConfiguration(commandContext).getTaskService();
        Task task = taskService.createTaskQuery().taskId(configuration).singleResult();
        if (task == null) {
            log.warn("Task with id {} not found", configuration);
            return;
        }
        //查询配置的超时策略
        UserTask userTask = ModelUtils.getUserTask(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
        if (userTask == null) {
            log.warn("UserTask not found for task definition key {} in process definition {}", task.getTaskDefinitionKey(), task.getProcessDefinitionId());
            return;
        }
        String timeoutStrategyValue = userTask.getAttributeValue(BpmnXMLConstants.FLOWABLE_EXTENSIONS_NAMESPACE, BpmnModelConstants.TIMEOUT_STRATEGY);
        try {
            TimeoutStrategy timeoutStrategy = TimeoutStrategy.fromValue(timeoutStrategyValue);
            handleTimeoutStrategy(task, timeoutStrategy);
        } catch (IllegalArgumentException e) {
            // 记录日志并处理异常
            log.error("Error processing task {}: {}", configuration, e.getMessage(), e);
        }
    }

    private void handleTimeoutStrategy(Task task, TimeoutStrategy timeoutStrategy) {
        switch (timeoutStrategy) {
            case AUTO_PASS:
                handleTaskOperation(task, TaskOperationEnum.AGREE.getCode(), "自动审批通过。审批人 [{}], 跳过原因 [任务超时]。");
                break;
            case AUTO_REJECT:
                handleTaskOperation(task, TaskOperationEnum.REJECT_BACK.getCode(), "自动审批驳回。审批人 [{}], 跳过原因 [任务超时]。");
                break;
            case ALERT:
                log.info("任务超时提醒：{}", task.getId());
                break;
            default:
                throw new IllegalArgumentException("未知的超时策略: " + timeoutStrategy.getValue());
        }
    }

    private void handleTaskOperation(Task task, String operationCode, String commentTemplate) {
        if (task.getAssignee() == null || task.getId() == null) {
            throw new IllegalArgumentException("任务分配人或任务ID不能为空");
        }
        TaskOperationDTO taskOperationDTO = new TaskOperationDTO();
        taskOperationDTO.setUserId(task.getAssignee());
        taskOperationDTO.setTaskId(task.getId());
        taskOperationDTO.setOperation(operationCode);
        String comment = StrFormatter.format(commentTemplate, task.getAssignee());
        taskOperationDTO.setComment(comment);
        taskOperationService.handleTaskOperation(taskOperationDTO);
    }

}
